%{
#include "shm_interface.h"
#include "lock.h"
#include "mmdb.h"
#include "calc.h"

//#define YYPARSE_PARAM  para
//#define YYLEX_PARAM para
#define yyerror(msg) my_yyerror(msg, YYPARSE_PARAM)

char *server_only="not allowed\n";
char *no_db="no database in open\n";
char *input_error="input error\n";
char *field_error="field not exist\n";
char *table_error="table not exist\n";

int my_yyerror(const char *msg,void *para)
{
	if(pthread_rwlock_trywrlock(&DB_lock)!=0)
	  Unlock_Cur_DB();
	char temp[MAX_COMMAND];
	strcpy(temp,msg);
	strcat(temp,"\n");
	if(((sql_sentence *)para)->sockfd != 1)
		strcat(temp,"\n\n\n");
	write(((sql_sentence *)para)->sockfd,temp,strlen(temp));
	return 0;
}

void parse(sql_sentence *para)
{
	parse_parm pp;
	strcpy(pp.buf,para->str);
	pp.length = strlen(para->str);
	pp.pos = 0;
	yylex_init(&pp.yyscanner);
	yyset_extra(&pp, pp.yyscanner);
	yyparse(&pp, pp.yyscanner,para);
	yylex_destroy(pp.yyscanner);
}
%}

%locations
%pure_parser
%parse-param {parse_parm *para}
%parse-param {void *scanner}
%parse-param {void *sql}
%lex-param {yyscan_t *scanner}


%union
{
	int intval;
	double floatval;
	char *strval;
	int subtok;
}
	
%token NAME
%token STRING
%token INTNUM APPROXNUM
%token COMPARISON
%left OR
%left AND
%left NOT
%left COMPARISON /* = < > <= >= */
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS

%token VARCHAR DOUBLE INTEGER
%token DROP DELETE CREATE
%token INFO QUIT SAVE OPEN LOAD PASSWD CREATEDB DELETEDB HELP REMOVEDB
%token FROM 
%token INSERT INTO
%token SELECT SET
%token TABLE
%token UPDATE VALUES WHERE  

%%
sql_list:
        sql{return 0;}
    |   sql_list sql{return 0;}
    ;


sql:	
		insert_statement
	|	select_statement
	|	delete_statement_searched
	|	create_statement
	|	update_statement_searched
	|	drop_statement
	|	query_info
	|	exit
	|	save_to_disk
	|   open_db
	|	create_db
	|	load_rd
	|	delete_db
	|	chg_pwd
	|	rmdb
	|	see_help
	;

rmdb:
	REMOVEDB';'
	{	
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB(); 
		if(remove_db()!=-1)
		  Free_table_lock();
		Unlock_Cur_DB();
	};

open_db:
	OPEN';'
	{
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB();
        Init_tb_locklist();
        open_db();
        Unlock_Cur_DB();
	};

create_db:
	CREATEDB';'
	{
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB();
        Init_tb_locklist();
		create_db();
        Unlock_Cur_DB();
	};

load_rd:
	LOAD';'
	{
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB(); 
		load_file();
		Unlock_Cur_DB();
	};

delete_db:
	DELETEDB';'
	{
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB(); 
		delete_db(); 
		Unlock_Cur_DB();
	};

chg_pwd:
	PASSWD';'
	{
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB(); 
		change_pwd();
		Unlock_Cur_DB();
	};

see_help:
	HELP';'
	{
		see_help(((sql_sentence *)para)->sockfd);
	};

save_to_disk:
	SAVE';'
	{
		Wlock_Cur_DB();
		save_all(((sql_sentence *)para)->sockfd);
		Unlock_Cur_DB();
	};

query_info:
	INFO';'
	{
		Rlock_Cur_DB();
		db_info(((sql_sentence *)para)->sockfd);
		Unlock_Cur_DB();
	};

exit:
	QUIT';'
	{
		if(((sql_sentence *)para)->sockfd != 1){
			error(server_only,((sql_sentence *)para)->sockfd);
			return 0;
		}
		Wlock_Cur_DB(); 
		Free_DB_lock();
		quit_sys();
	};

opt_column_commalist:
	|	'(' column_commalist ')'
	;

/*----------------------------------------------------------------------------------------------*/
/*------------------------------     CREATE TABLE        ---------------------------------------*/
/*----------------------------------------------------------------------------------------------*/
create_statement:
	create_ TABLE table '(' base_table_element_commalist ')'';'
	{
		Create_Table *create;
		((sql_sentence *)para)->create_sentence->Tab = ((sql_sentence *)para)->table_struct;
		if(!((sql_sentence *)para)->cur_table_field){  //判断field是否是空
			error("field cannot be empty\n",((sql_sentence *)para)->sockfd);
			Unlock_Cur_DB();
			return 0;
		}
		if(((sql_sentence *)para)->table_struct->Field_num >= NUM_OF_COLU){  //判断field数目是否超出系统规定最大数目
			error("too many field\n",((sql_sentence *)para)->sockfd);
			Unlock_Cur_DB();
			return 0;
		}
		create = ((sql_sentence *)para)->create_sentence;
		
		ExeCreateTable(create, ((sql_sentence *)para)->sockfd);
		Free_Create(create);
		Unlock_Cur_DB();
			
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_end));
		char te[1024];
		print_time(te, ((sql_sentence *)para)->sockfd, ((sql_sentence *)para)->time_st , ((sql_sentence *)para)->time_end);
	};

create_:
	CREATE
	{
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_st));
		Wlock_Cur_DB();
		
		if(!ptr){
			if(((sql_sentence *)para)->sockfd != 1)
			  error(no_db,((sql_sentence *)para)->sockfd);
			else
			  printf("%s",no_db);
			Unlock_Cur_DB();
			return 0;
		}
		((sql_sentence *)para)->create_sentence = malloc(sizeof(Create_Table));
		((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
		Init_Create_Table((((sql_sentence *)para))->create_sentence);
		Init_Table(((sql_sentence *)para)->table_struct);
	};

base_table_element_commalist:
		base_table_element
	|	base_table_element_commalist ',' base_table_element
	; 

base_table_element: 
		column_def
	;

column_def:
	{
		((sql_sentence *)para)->cur_table_field = malloc(sizeof(Field));
		Init_Field(((sql_sentence *)para)->cur_table_field);
	}
	column date_type
	{
		Field *f = ((sql_sentence *)para)->table_struct->Field_list;
		for(;f!=NULL;f=f->Next_Field){
			if(!strcmp(f->Field_Name,$<strval>1)){
				error(input_error,((sql_sentence *)para)->sockfd);
				Unlock_Cur_DB();
				return 0;
			}
		}
		strcpy(((sql_sentence *)para)->cur_table_field->Field_Name,$<strval>1);
        AddField(((sql_sentence *)para)->table_struct,((sql_sentence *)para)->cur_table_field);
	};

/*---------------------------------------------------------------------------*/
/*----------------------------  DELETE	----------------------------------*/
/*---------------------------------------------------------------------------*/
delete_statement_searched:
	delete_ FROM delete_table opt_where_clause';'
	{
			Delete *del;
			((sql_sentence *)para)->delete_sentence->Select_where = ((sql_sentence *)para)->where_struct;
			((sql_sentence *)para)->delete_sentence->Select_Table = ((sql_sentence *)para)->table_struct;
            del = ((sql_sentence *)para)->delete_sentence;
			ExeDelete(del,((sql_sentence *)para)->sockfd);
			char temp[1024];
			strcpy(temp,del->Select_Table->Table_Name);
			Free_Delete(del);
			Unlock_Table(temp);
			Unlock_Cur_DB();
			
			clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_end));
			char te[1024];
			print_time(te, ((sql_sentence *)para)->sockfd, ((sql_sentence *)para)->time_st , ((sql_sentence *)para)->time_end);
	};

delete_:
	DELETE
	{
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_st));
		Rlock_Cur_DB();
		
		if(!ptr){
			if(((sql_sentence *)para)->sockfd != 1)
			  error(no_db,((sql_sentence *)para)->sockfd);
			else
			  printf("%s",no_db);
			Unlock_Cur_DB();
			return 0;
		}
		((sql_sentence *)para)->delete_sentence = malloc(sizeof(Delete));
		((sql_sentence *)para)->where_struct = malloc(sizeof(Where));
		((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
		Init_Delete(((sql_sentence *)para)->delete_sentence);
		Init_Where(((sql_sentence *)para)->where_struct);
		Init_Table(((sql_sentence *)para)->table_struct);
	};
delete_table:
	table
	{
		Wlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
	};

/*---------------------------------------------------------------------------*/
/*----------------------------  INSERT  ---------------------------------------*/
/*---------------------------------------------------------------------------*/
insert_statement:
		insert_ INTO insert_table opt_column_commalist values_or_query_spec';'
		{
			int i = 0;
			Insect *insect;
            int tb_id;
			if((tb_id=ExistTable(((sql_sentence *)para)->table_struct->Table_Name)) == -1){
				error(table_error,((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			int fd_num = Get_Field_Num(tb_id);
			if(fd_num != ((sql_sentence *)para)->table_struct->Field_num){
			    Field *f;
			    Table *New_Table = malloc(sizeof(Table));
			    Init_Table(New_Table);
			    int j;
			    for(j=0;j<fd_num;j++){
			       Field *cf = malloc(sizeof(Field));
			       Init_Field(cf);
			       Get_Field(tb_id,j,cf);                                        
			       for(f=((sql_sentence *)para)->table_struct->Field_list;f;f=f->Next_Field){
			          if(!strcmp(f->Field_Name,cf->Field_Name)){
						  Field *ff = malloc(sizeof(Field));
						  Init_Field(ff);
						  *ff = *f;
						  ff->Next_Field = NULL;
			              		  AddField(New_Table,ff);
						  break;
					  }
			       }
			       if(!f){
			          //set the default values while the field is null;
			          switch(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,cf->Field_Name))
			          {
			          case INTX:cf->date_type = INTX;cf->Int_Val = 0;break;
			          case DOUBLEX:cf->date_type  = DOUBLEX;cf->Double_Val = 0.0;break;
			          case STRINGX:cf->date_type = STRINGX;strcpy(cf->Str_Val,"null");break;
			          default:break;
			          }
			          AddField(New_Table,cf);
			       }
			    }
			    ((sql_sentence *)para)->table_struct->Field_list = New_Table->Field_list;
                	    New_Table->Field_list = NULL;
                	    free(New_Table);            
			}
			else
			{
			   if(((sql_sentence *)para)->cur_table_field)
			   {
				error(input_error,((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return;
			   }
			}

			((sql_sentence *)para)->insect_sentence->Tab=((sql_sentence *)para)->table_struct;
            		insect = ((sql_sentence *)para)->insect_sentence;

			ExeInsect(insect,((sql_sentence *)para)->sockfd);
			char temp[1024];
			strcpy(temp,insect->Tab->Table_Name);
			Free_Insect(insect);
			Unlock_Table(temp);
			Unlock_Cur_DB();
			
			clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_end));
			char te[1024];
			print_time(te, ((sql_sentence *)para)->sockfd, ((sql_sentence *)para)->time_st , ((sql_sentence *)para)->time_end);
		}
		;

insert_:
	INSERT
	{
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_st));
		Rlock_Cur_DB();
			
		if(!ptr){
			if(((sql_sentence *)para)->sockfd != 1)
			  error(no_db,((sql_sentence *)para)->sockfd);
			else
			  printf("%s",no_db);
			Unlock_Cur_DB();
			return 0;
		}
			
		((sql_sentence *)para)->insect_sentence = malloc(sizeof(Insect));
		((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
        Init_Table(((sql_sentence *)para)->table_struct);
		};

insert_table:
	table
	{
		Wlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
	};

values_or_query_spec:
	{
		if(((sql_sentence *)para)->table_struct->Field_list==NULL){
			int tb_id;
			if((tb_id=ExistTable(((sql_sentence *)para)->table_struct->Table_Name))==-1){
				error(table_error,((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			int fd_num = Get_Field_Num(tb_id);
			int j;
			Field *f;
			for(j=0;j<fd_num;j++){
				f = malloc(sizeof(Field));
			 	Init_Field(f);
				Get_Field(tb_id,j,f);
				AddField(((sql_sentence *)para)->table_struct,f); 
			}
			((sql_sentence *)para)->cur_table_field = ((sql_sentence *)para)->table_struct->Field_list;
		}
	}
	VALUES '(' insert_atom_commalist ')'
	;

insert_atom_commalist:
		insert_atom
	|	insert_atom_commalist ',' insert_atom
	;

insert_atom:
	atom 
	{
		if(!((sql_sentence *)para)->cur_table_field){
			error(input_error,((sql_sentence *)para)->sockfd);
			Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
			Unlock_Cur_DB();
			return 0;
		}
		switch(((sql_sentence *)para)->Cur_date_type)
		{
		case INTX:
			if(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,((sql_sentence *)para)->cur_table_field->Field_Name)!=INTX){
				error("a field type error:should be INTEGER\n",((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			((sql_sentence *)para)->cur_table_field->Int_Val = $<intval>1;
			break;
		case DOUBLEX:
			 if(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,((sql_sentence *)para)->cur_table_field->Field_Name)!=DOUBLEX){
				error("a filed type error:should be DOUBLE\n",((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			((sql_sentence *)para)->cur_table_field->Double_Val = $<floatval>1;
			break;
		case STRINGX:
			 if(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,((sql_sentence *)para)->cur_table_field->Field_Name)!=STRINGX){
				error("a field type error:should be VARCHAR",((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			strcpy(((sql_sentence *)para)->cur_table_field->Str_Val , $<strval>1);
			break;
		default:
			break;
		}
		((sql_sentence *)para)->cur_table_field->date_type = ((sql_sentence *)para)->Cur_date_type;
		((sql_sentence *)para)->cur_table_field = ((sql_sentence *)para)->cur_table_field->Next_Field;
	};



/*---------------------------------------------------------------------------*/
/*----------------------------  UPDATE  --------------------------------------*/
/*---------------------------------------------------------------------------*/
update_statement_searched:
	update_ update_table SET assignment_commalist opt_where_clause';'
	{
		Update *update;
		((sql_sentence *)para)->update_sentence->Tab = ((sql_sentence *)para)->table_struct; 
		((sql_sentence *)para)->update_sentence->Select_where = ((sql_sentence *)para)->where_struct;
		update = ((sql_sentence *)para)->update_sentence;
		ExeUpdate(update,((sql_sentence *)para)->sockfd);
		char temp[1024];
		strcpy(temp,update->Tab->Table_Name);
		Free_Update(update);
		Unlock_Table(temp);
		Unlock_Cur_DB();
		
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_end));
		char te[1024];
		print_time(te, ((sql_sentence *)para)->sockfd, ((sql_sentence *)para)->time_st , ((sql_sentence *)para)->time_end);
	};

update_:
	UPDATE
	{
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_st));
		Rlock_Cur_DB();
		
		if(!ptr){
			if(((sql_sentence *)para)->sockfd != 1)
			  error(no_db,((sql_sentence *)para)->sockfd);
			else
			  printf("%s",no_db);
			Unlock_Cur_DB();
			return 0;
		}
		
		((sql_sentence *)para)->update_sentence = malloc(sizeof(Update));
		((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
		((sql_sentence *)para)->where_struct = malloc(sizeof(Where));
		Init_Update(((sql_sentence *)para)->update_sentence);
		Init_Table(((sql_sentence *)para)->table_struct);
		Init_Where(((sql_sentence *)para)->where_struct);
	};

update_table:
	table
	{
		Wlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
	};

assignment_commalist:
	|	assignment
	|	assignment_commalist ',' assignment
	;

assignment:
	column COMPARISON atom
	{
		Field *f = malloc(sizeof(Field));
		Init_Field(f);
		strcpy(f->Field_Name,$<strval>1);
		strcpy(f->Table_Name,((sql_sentence *)para)->table_struct->Table_Name);
		if(strcmp($<strval>2,"=")){
			error(input_error,((sql_sentence *)para)->sockfd);
			Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
			Unlock_Cur_DB();
			return 0;
		}
		
		if(ExistField(f->Table_Name,f->Field_Name) == -2){  //update xxx set field=... 检查是否存在field这个属性
			error(field_error,((sql_sentence *)para)->sockfd);
			Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
			Unlock_Cur_DB();
			return 0;
		}
		switch(((sql_sentence *)para)->Cur_date_type)
		{
		case INTX:
			if(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,f->Field_Name)!=INTX){
				error("a field type error:should be INTEGER\n",((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			f->date_type = INTX;
			f->Int_Val = $<intval>3;
			break;
		case DOUBLEX:
			if(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,f->Field_Name)!=DOUBLEX){
				error("a field type error:should be DOUBLE\n",((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			f->date_type = DOUBLEX;
			f->Double_Val = $<floatval>3;
			break;
		case STRINGX:
			if(Field_DateType(((sql_sentence *)para)->table_struct->Table_Name,f->Field_Name)!=STRINGX){
				error("a field type error:should be VARCHAR\n",((sql_sentence *)para)->sockfd);
				Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
				return 0;
			}
			f->date_type = STRINGX;
			strcpy(f->Str_Val , $<strval>3);
			break;
		default:
			break;
		}
                        
		if(ExistField(((sql_sentence *)para)->table_struct->Table_Name,f->Field_Name)==-2){
			error(field_error,((sql_sentence *)para)->sockfd);
			Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
				Unlock_Cur_DB();
			return 0;
		}
		AddField(((sql_sentence *)para)->table_struct,f);
	};

opt_where_clause:
		/* empty */
	|	where_clause
	;

		
		
/*---------------------------------------------------------------------------*/
/*----------------------------  DROP  --------------------------------------*/
/*---------------------------------------------------------------------------*/
drop_statement:
	drop_ table';'
	{
		strcpy(((sql_sentence *)para)->drop_sentence->name,((sql_sentence *)para)->table_struct->Table_Name);
		ExeDropTable(((sql_sentence *)para)->drop_sentence,((sql_sentence *)para)->sockfd);
		free(((sql_sentence *)para)->table_struct);
        Free_Drop(((sql_sentence *)para)->drop_sentence);
		Unlock_Cur_DB();
	}
	;
drop_:
		DROP
		{
			Wlock_Cur_DB();
	
			if(!ptr){
				if(((sql_sentence *)para)->sockfd != 1)
				  error(no_db,((sql_sentence *)para)->sockfd);
				else
				  printf("%s",no_db);
				Unlock_Cur_DB();
				return 0;
			}
			((sql_sentence *)para)->drop_sentence  = malloc(sizeof(Drop_Table));
			((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
            Init_Table(((sql_sentence *)para)->table_struct);
		};





/*---------------------------------------------------------------------------*/
/*----------------------------  SELECT  --------------------------------------*/
/*---------------------------------------------------------------------------*/

select_statement:
	select_ selection table_exp';'
	{ 
		Field *fd;
		Select *select;
		((sql_sentence *)para)->select_sentence->Select_list = ((sql_sentence *)para)->table_struct;
		((sql_sentence *)para)->select_sentence->Select_where = ((sql_sentence *)para)->where_struct;
		fd = ((sql_sentence *)para)->select_sentence->Select_list->Field_list;
		int tb_id =  ExistTable(((sql_sentence *)para)->table_struct->Table_Name);
		int i;
		
		//如果是* ,选择所有字段
		if(!fd){ //*
			for(i=0;i<Get_Field_Num(tb_id);i++){
				Field *f = malloc(sizeof(Field));
				Init_Field(f);
				Get_Field(tb_id,i,f);
				AddField(((sql_sentence *)para)->table_struct,f);           
			}            
		}
		else{  //指定列
			Field *f = ((sql_sentence *)para)->table_struct->Field_list;
			for(;f;f = f->Next_Field)
				if(ExistField(((sql_sentence *)para)->table_struct->Table_Name,f->Field_Name)==-2){
					error(field_error,((sql_sentence *)para)->sockfd);
					Unlock_Cur_DB();
					return;
				}
		}
		select = ((sql_sentence *)para)->select_sentence;
		ExeSelect(select,((sql_sentence *)para)->sockfd);
		
		char temp[MAX_NAME];
		strcpy(temp,select->Select_list->Table_Name);
		Free_Select(select);
		Unlock_Table(temp);
		Unlock_Cur_DB();
		
			
        clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_end));
        char te[1024];
        print_time(te, ((sql_sentence *)para)->sockfd, ((sql_sentence *)para)->time_st , ((sql_sentence *)para)->time_end);
	};

select_:
	SELECT
	{
		clock_gettime(CLOCK_MONOTONIC,&(((sql_sentence *)para)->time_st));
		Rlock_Cur_DB();
		
		if(!ptr){
			if(((sql_sentence *)para)->sockfd != 1)
			  error(no_db,((sql_sentence *)para)->sockfd);
			else
			  printf("%s",no_db);
			Unlock_Cur_DB();
			return 0;
		}
		
		((sql_sentence *)para)->select_sentence = malloc(sizeof(Select));
		((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
		((sql_sentence *)para)->where_struct = malloc(sizeof(Where));
		Init_Select(((sql_sentence *)para)->select_sentence);
		Init_Table(((sql_sentence *)para)->table_struct);
		Init_Where(((sql_sentence *)para)->where_struct);
	}

selection:
		scalar_exp_commalist        
	|	
		'*'
	{   
		((sql_sentence *)para)->table_struct = malloc(sizeof(Table));
		Init_Table(((sql_sentence *)para)->table_struct);
	    ((sql_sentence *)para)->select_sentence->Select_list = ((sql_sentence *)para)->table_struct;
	};

table_exp:
		from_clause   
		opt_where_clause  
	;
from_clause:
		FROM select_table   
		{
			WhereTable *wt= malloc(sizeof(WhereTable));
			Init_WhereTable(wt);
			strcpy(((sql_sentence *)para)->table_struct->Table_Name,$<strval>2);
			strcpy(wt->name, $<strval>2);
            Rlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
			AddWhereTable(((sql_sentence *)para)->where_struct,wt);
		}
	;
select_table:
		table 
	;

column_commalist:
		column2
	|	column_commalist ',' column2
	;
column2:
		NAME
		{
			Field *f = malloc(sizeof(Field));
			int r = ExistField(((sql_sentence *)para)->table_struct->Table_Name,$<strval>1);
			if(r==-1){
				error(table_error,((sql_sentence *)para)->sockfd); 
				Unlock_Cur_DB();
				return 0;
			}
			if(r==-2){
				error(field_error,((sql_sentence *)para)->sockfd); 
				Unlock_Cur_DB();
				return 0;
			}
			Init_Field(f);
			strcpy(f->Field_Name , $<strval>1);
                        
            AddField(((sql_sentence *)para)->table_struct,f);
			if(((sql_sentence *)para)->cur_table_field != ((sql_sentence *)para)->table_struct->Field_list)
			    ((sql_sentence *)para)->cur_table_field = ((sql_sentence *)para)->table_struct->Field_list;
		}
		;
where_clause:
		WHERE search_condition
	;

/* ---------------------------------------------------------------------*/
/* ---------------------search conditions -------------------------------*/
/* ----------------------------------- -------------------------------*/

search_condition:
	|
	or_search_condition	
	{
		((sql_sentence *)para)->where_struct->where_type = ORX;
	}
	|
	and_search_condition
	{
		((sql_sentence *)para)->where_struct->where_type = ANDX;
	}
	|	predicate
	;

or_search_condition:
	    or_search_condition OR or_search_condition
	|   predicate
	;

and_search_condition:
		and_search_condition AND and_search_condition
	|   predicate
	;

predicate:
		comparison_predicate 
	;

comparison_predicate:
	scalar_exp COMPARISON scalar_exp
	{
		if(!strcmp($<strval>2,"="))
		  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->opt = EQU;
		else{
			if(!strcmp($<strval>2,">"))
			  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->opt = THAN;
			else 
			  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->opt = LESS;
		}
	};

scalar_exp:
	atom
	{
		Atom *am = malloc(sizeof(Atom));
		Field *f = malloc(sizeof(Field));
		Init_Field(f);
        	Init_Atom(am);
		if(!((sql_sentence *)para)->where_struct->Where_table_list){
			WhereTable *wt = malloc(sizeof(WhereTable));
			Init_WhereTable(wt);
			AddWhereTable(((sql_sentence *)para)->where_struct,wt);
		}
		switch(((sql_sentence *)para)->Cur_date_type)
		{
			case INTX:
				f->date_type = INTX;
				f->Int_Val = $<intval>1;
				break;
			case DOUBLEX:
				f->date_type = DOUBLEX;
				f->Double_Val = $<floatval>1;
				break;
			case STRINGX:
				f->date_type = STRINGX;
				strcpy(f->Str_Val , $<strval>1);
				break;
		}
		am->Atom_field = f;
		am->Atom_type = VALUE;
		if(!((sql_sentence *)para)->where_struct->Where_table_list->last_node || ((sql_sentence *)para)->where_struct->Where_table_list->last_node->R_atom!=NULL){
			Where_node *wn = malloc(sizeof(Where_node));
			Init_Where_node(wn);
			AddWhereNode(((sql_sentence *)para)->where_struct,wn,NULL);
		}
		if(!((sql_sentence *)para)->where_struct->Where_table_list->last_node->L_atom)
		  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->L_atom = am;
		else 
		  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->R_atom = am;
	}  
	|
	field_ref 
	{
		if(ExistField(((sql_sentence *)para)->table_struct->Table_Name,$<strval>1)==-2)
		{
		   error(field_error,((sql_sentence *)para)->sockfd);
		   Unlock_Table(((sql_sentence *)para)->table_struct->Table_Name);
		   Unlock_Cur_DB();
		   return;
		}
		Atom *am = malloc(sizeof(Atom));
		Field *f = malloc(sizeof(Field));
		Init_Field(f);
        	Init_Atom(am);
		if(!((sql_sentence *)para)->where_struct->Where_table_list){
			WhereTable *wt = malloc(sizeof(WhereTable));
			Init_WhereTable(wt);
			AddWhereTable(((sql_sentence *)para)->where_struct,wt);
		}
		strcpy(f->Field_Name , $<strval>1);
		am->Atom_field = f;
		am->Atom_type = FIELD;
		if(!((sql_sentence *)para)->where_struct->Where_table_list->last_node || ((sql_sentence *)para)->where_struct->Where_table_list->last_node->R_atom!=NULL){
			Where_node *wn = malloc(sizeof(Where_node));
			Init_Where_node(wn);
			AddWhereNode(((sql_sentence *)para)->where_struct,wn,NULL);
		}
		if(!((sql_sentence *)para)->where_struct->Where_table_list->last_node->L_atom)
		  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->L_atom = am;
		else  
		  ((sql_sentence *)para)->where_struct->Where_table_list->last_node->R_atom = am;
	};

scalar_exp_commalist:
		column_ref    
	|	scalar_exp_commalist ',' column_ref   
	;

field_ref:
	NAME
	{
		$<strval>$ = $<strval>1;
	};


atom:
	STRING
	{
		int i=0;
		strcpy(((sql_sentence *)para)->str, $<strval>1);
		((sql_sentence *)para)->Cur_date_type = STRINGX;
		for(;i<strlen(((sql_sentence *)para)->str);i++){
			((sql_sentence *)para)->str[i]=((sql_sentence *)para)->str[i+1];
			if(((sql_sentence *)para)->str[i]=='\"')
			  break;
		}
		((sql_sentence *)para)->str[i]='\0';
		strcpy($<strval>$ , ((sql_sentence *)para)->str);
	}
	|
	INTNUM
	{
		((sql_sentence *)para)->Cur_date_type = INTX;
		$<intval>$ = $<intval>1;
	}
	|
	APPROXNUM
	{
		((sql_sentence *)para)->Cur_date_type = DOUBLEX;
		$<floatval>$ = $<floatval>1;
	};


table:
	NAME
	{
		$<strval>$=$<strval>1;
		if(((sql_sentence *)para)->table_struct){
			strcpy(((sql_sentence *)para)->table_struct->Table_Name , $<strval>1);
			if(((sql_sentence *)para)->create_sentence){
				if(ExistTable($<strval>1)!=-1){	
					error("table exists\n",((sql_sentence *)para)->sockfd);
					Unlock_Cur_DB();
					return 0;
				}
			}
			else{
				if(ExistTable($<strval>1)==-1){
					error(table_error,((sql_sentence *)para)->sockfd);
					Unlock_Cur_DB();
					return 0;
				}
			}
		}
	};

column_ref:
	NAME            
	{
		Field *f = malloc(sizeof(Field));          
		Init_Field(f);
		strcpy(f->Field_Name,$<strval>1);
		AddField(((sql_sentence *)para)->table_struct,f);
	};


date_type:
	VARCHAR '(' INTNUM ')'
	{
		((sql_sentence *)para)->cur_table_field->str_len = $<intval>3;
		((sql_sentence *)para)->cur_table_field->date_type = STRINGX;
	}
	|
	INTEGER '(' INTNUM ')'
	{
		((sql_sentence *)para)->cur_table_field->str_len = $<intval>3;
		((sql_sentence *)para)->cur_table_field->date_type = INTX;
	}
	|
	DOUBLE '(' INTNUM ')'
	{
		((sql_sentence *)para)->cur_table_field->str_len = $<intval>3;
		((sql_sentence *)para)->cur_table_field->date_type = DOUBLEX;
	};

column:
	NAME
	{
		$<strval>$ = $<strval>1;
	};
%%
